package com.xwc.cloud.support.loadbalancer;

import com.xwc.cloud.support.loadbalancer.feign.ForwardedRouterRequestInterceptor;
import com.xwc.cloud.support.loadbalancer.feign.ServletExtractRouterIp;
import com.xwc.cloud.support.loadbalancer.gateway.DefaultGatewayExtractRouterIp;
import com.xwc.cloud.support.loadbalancer.gateway.ReactiveExtractTargetRouter;
import com.xwc.cloud.support.loadbalancer.zuul.ExtractTargetRouter;
import com.xwc.cloud.support.loadbalancer.zuul.RouterIpHeaderWriteFilter;
import com.xwc.cloud.support.loadbalancer.zuul.DefaultZuulExtractRouterIp;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 类描述：自动化配置ribbon-support的配置类
 * 作者：徐卫超 (cc)
 * 时间 2022/4/7 9:44
 */
@Configuration
@EnableConfigurationProperties
@ConditionalOnProperty(value = LoadbalancerSupportConfiguration.AUTO_CONFIG, havingValue = "true")
public class LoadbalancerSupportConfiguration {

    public static final String AUTO_CONFIG = "spring.cloud.loadbalancer.support.enable";

    @Configuration
    @ConditionalOnClass(name = {"feign.RequestInterceptor", "org.springframework.cloud.netflix.ribbon.RibbonClients"})
    @RibbonClients(defaultConfiguration = ServletRibbonConfig.class)
    public static class RuleFeignConfig {
        @Bean
        @ConditionalOnMissingBean
        public ForwardedRouterRequestInterceptor forwardedRouterRequestInterceptor(
                LoadbalancerSupportProperties ribbonSupportProperties, ServletExtractRouterIp servletExtractRouterIp) {

            return new ForwardedRouterRequestInterceptor(ribbonSupportProperties, servletExtractRouterIp);
        }

        @Bean
        @ConditionalOnMissingBean
        public ServletExtractRouterIp servletExtractRouterIp(LoadbalancerSupportProperties ribbonSupportProperties) {
            return new ServletExtractRouterIp(ribbonSupportProperties);
        }
    }

    @Configuration
    @LoadBalancerClients(defaultConfiguration = ReactorLoadbalancerConfig.class)
    @ConditionalOnClass(name = {"org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter"})
    public static class RuleGatewayConfig {

        @Bean
        @ConditionalOnMissingBean
        public ReactiveExtractTargetRouter reactiveExtractTargetRouter(LoadbalancerSupportProperties ribbonSupportProperties) {
            return new DefaultGatewayExtractRouterIp(ribbonSupportProperties);
        }
    }

    @Configuration
    @RibbonClients(defaultConfiguration = ServletRibbonConfig.class)
    @ConditionalOnClass(name = {"org.springframework.cloud.netflix.ribbon.RibbonClients", "com.netflix.zuul.ZuulFilter"})
    public static class RuleZuulConfig {
        @Bean
        @ConditionalOnMissingBean
        public RouterIpHeaderWriteFilter ruleFilter(LoadbalancerSupportProperties loadbalancerSupportProperties,
                                                    DefaultZuulExtractRouterIp defaultZuulExtractRouterIp) {
            return new RouterIpHeaderWriteFilter(loadbalancerSupportProperties, defaultZuulExtractRouterIp);
        }

        @Bean
        @ConditionalOnMissingBean
        public ExtractTargetRouter zuulExtractRouterIp(LoadbalancerSupportProperties loadbalancerSupportProperties) {
            return new DefaultZuulExtractRouterIp(loadbalancerSupportProperties);
        }
    }

    @Bean
    @ConfigurationProperties(value = "spring.cloud.loadbalancer.support")
    public LoadbalancerSupportProperties loadbalancerSupportProperties() {
        return new LoadbalancerSupportProperties();
    }


}
